TOOL.Category    = "Conna's Tools"
TOOL.Name        = "#Command Box Tool"
TOOL.Command     = nil
TOOL.ConfigName  = ""

// Disallowed

TOOL.Disallowed = {
	"bind",
	"quit",
	"quti",
	"exit",
	"hairball",
	"ent_fire",
	"rcon",
	"cl_",
	"net_",
	"mat_",
	"r_",
	"g_",
	"disconnect",
	"alias",
	"name"
}

// ConVars

TOOL.ClientConVar["Model"] = "models/props_lab/reciever01a.mdl"
TOOL.ClientConVar["Command"] = ""
TOOL.ClientConVar["Key"] = "5"

// Register

cleanup.Register("commandboxes")

// Console

CreateConVar("sbox_maxcommandboxes", 10, FCVAR_NOTIFY)

// Client

if (CLIENT) then
	// Tool
	
	language.Add("Tool_commandbox_name", "Command Box Tool")
	language.Add("Tool_commandbox_desc", "Command Box which runs console command when you press a key")
	language.Add("Tool_commandbox_0", "Left click to spawn a Command Box")
	
	// Other
	
	language.Add("Undone_commandbox", "Undone Command Box")
	language.Add("SBoxLimit_commandboxes", "You've hit the Command Boxes limit!")
	language.Add("Cleanup_commandboxes", "Command Boxes")
	language.Add("Cleaned_commandboxes", "Cleaned up all Command Boxes")
end

// Message

function TOOL:Message(Text)
	if SERVER then
		self:GetOwner():SendLua("GAMEMODE:AddNotify('"..Text.."', NOTIFY_GENERIC, 10)")
		self:GetOwner():SendLua("surface.PlaySound('ambient/water/drip"..math.random(1, 4)..".wav')")
	end
end

// Left click

function TOOL:LeftClick(Trace)
	if(CLIENT) then
		return true
	end
	
	// Locals
	
	local Player = self:GetOwner()

	local Model = self:GetClientInfo("Model")
	local Command = self:GetClientInfo("Command")
	local Key = self:GetClientNumber("Key")
	
	// SS
	
	if (SS and SS.ConsoleCommand and SS.ConsoleCommand.List) then
		for K, V in pairs(SS.ConsoleCommand.List) do
			if (string.find(string.lower(Command), string.lower(K))) then
				if not (SS.Flags.PlayerHas(Player, V.Restrict)) then
					local Access = {}
					
					for B, J in pairs(V.Restrict) do
						if not (SS.Flags.PlayerHas(Player, J)) then
							table.insert(Access, J)
						end
					end
					
					Access = table.concat(Access, " or ")
					
					SS.PlayerMessage(Player, "You do not have access for "..K..", you need "..Access.." flags", 1)
					
					return false
				end
			end
		end
	end
	
	// Check
	
	for K, V in pairs(self.Disallowed) do
		if (string.find(string.lower(Command), string.lower(V))) then
			self:Message("Commands can not include the word \""..V.."\"!")
			
			return false
		end
	end
	
	if (Trace.Entity and Trace.Entity:IsValid() and Trace.Entity:GetClass() == "gmod_commandbox") then
		local Entity = Trace.Entity
		
		// Other
		
		Entity:GetTable():SetEntityCommand(Command)
		
		self:Message("Properties changed for Command Box!")
		
		return true
	end
	
	local Ang = Trace.HitNormal:Angle()
	
	Ang.pitch = Ang.pitch + 90

	local Box = CreateCommandBox(Player, Ang, Trace.HitPos, Model, Key, Command)
	
	if not (Box) then return false end
	
	local Minimum = Box:OBBMins()
	
	Box:SetPos(Trace.HitPos - Trace.HitNormal * Minimum.z)
	
	undo.Create("commandbox")
	
	if (Trace.Entity and not Trace.Entity:IsWorld()) then
		local Weld = constraint.Weld(Box, Trace.Entity, 0, Trace.PhysicsBone, 0, true, true)
		
		undo.AddEntity(Weld)
		
		Player:AddCleanup("commandboxes", Weld)
		
		Box:GetPhysicsObject():EnableCollisions(false)
	end
	
	undo.AddEntity(Box)
	
	undo.SetPlayer(Player)
	
	undo.Finish()
	
	Player:AddCount("commandboxes", Box)
	
	Player:AddCleanup("commandboxes", Box)
	
	self:Message("Command Box has been created!")
	
	return true, Box
end

// Make it

if (SERVER) then
	// Create command box
	
	function CreateCommandBox(Player, Ang, Pos, Model, Key, Command, Nocollide, Vel, Avel, Frozen)
		if (!Player:CheckLimit("commandboxes")) then return false end
		
		local Box = ents.Create("gmod_commandbox")
		
		Box:SetModel(Model)
		Box:SetAngles(Ang)
		Box:SetPos(Pos)
		Box:Spawn()
		
		// Set the entities owner
		
		Box:GetTable():SetPlayer(Player)
		
		// Other
		
		Box:GetTable():SetEntityKey(Key)
		Box:GetTable():SetEntityCommand(Command)
		
		// Numpad

		numpad.OnUp(Player, Key, "CommandBox.Pressed", Box, false)
		
		// Frozen and nocollide
		
		if (Frozen) then Box:GetPhysicsObject():EnableMotion(false) end
		
		if (Nocollide)then Box:GetPhysicsObject():EnableCollisions(false) end
		
		return Box
	end
	
	duplicator.RegisterEntityClass("gmod_commandbox", CreateCommandBox, "Ang", "Pos", "Model", "Key", "Command", "Nocollide", "Vel", "Avel", "Frozen")
end

// Control panel

function TOOL.BuildCPanel(Panel)
	Panel:AddControl("Header", {Text = "#Tool_commandbox_name", Description = "#Tool_commandbox_desc"})

	local Models = {}
	
	Models["Reciever"] = {}
	Models["Reciever"]["commandbox_Model"] = "models/props_lab/reciever01a.mdl"
	
	Models["Monitor"] = {}
	Models["Monitor"]["commandbox_Model"] = "models/props_lab/monitor02.mdl"
	
	Panel:AddControl("ComboBox", {Label = "Model", Options = Models, MenuButton = 0})
	
	Panel:AddControl("Numpad", {Label = "Key", Command = "commandbox_Key", ButtonSize = 22})
	
	Panel:AddControl("TextBox", {Label = "Command", MaxLength = "255", Command = "commandbox_Command"})
end

// Ghost

function TOOL:UpdateGhostBox(Entity, Player)
	if (!Entity) then return end
	
	if (!Entity:IsValid()) then return end

	local TR = utilx.GetPlayerTrace(Player, Player:GetCursorAimVector())
	
	local Trace = util.TraceLine(TR)
	
	if (!Trace.Hit) then return end
	
	if (Trace.Entity && Trace.Entity:GetClass() == "gmod_commandbox" || Trace.Entity:IsPlayer()) then
		Entity:SetNoDraw(true)
		
		return
	end
	
	local Ang = Trace.HitNormal:Angle()
	
	Ang.pitch = Ang.pitch + 90
	
	local Minimum = Entity:OBBMins()
	
	Entity:SetPos(Trace.HitPos - Trace.HitNormal * Minimum.z)
	
	Entity:SetAngles(Ang)
	
	Entity:SetNoDraw(false)
end

// Think

function TOOL:Think()
	if (self:GetOwner() and self:GetOwner():IsPlayer()) then
		if (!self.GhostEntity || !self.GhostEntity:IsValid() || self.GhostEntity:GetModel() != self:GetClientInfo("Model")) then
			self:MakeGhostEntity(self:GetClientInfo("Model"), Vector(0, 0, 0), Angle(0, 0, 0) )
		end
		
		self:UpdateGhostBox(self.GhostEntity, self:GetOwner())
	end
end